package com.iflytek.jcy.supervise.datastore.pgsql;

import javax.sql.DataSource;

import com.iflytek.jcy.supervise.datastore.api.DataSourceHolder;
import com.iflytek.jcy.supervise.datastore.config.DataStoreAutoConfiguration;
import com.iflytek.jcy.supervise.datastore.config.DataStoreDataSourceProperties;
import com.zaxxer.hikari.HikariConfigMXBean;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceUnwrapper;
import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;
import org.springframework.boot.jdbc.metadata.HikariDataSourcePoolMetadata;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

/**
 * @author <a href=mailto:ktyi@iflytek.com>伊开堂</a>
 * @date 2022/10/12
 */
@Configuration
@AutoConfigureBefore(DataStoreAutoConfiguration.class)
@EnableConfigurationProperties(DataStoreDataSourceProperties.class)
public class DataStorePgsqlAutoConfiguration {

    DataSourcePoolMetadataProvider hikariPoolDataSourceMetadataProvider() {
        return (dataSource) -> {
            HikariDataSource hikariDataSource = DataSourceUnwrapper.unwrap(dataSource, HikariConfigMXBean.class,
                                                                           HikariDataSource.class);
            if (hikariDataSource != null) {
                return new HikariDataSourcePoolMetadata(hikariDataSource);
            }
            return null;
        };
    }

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(HikariDataSource.class)
    @ConditionalOnMissingBean(DataSourceHolder.class)
    @ConditionalOnProperty(name = "datastore.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true)
    static class Hikari {

        @Bean(destroyMethod = "close")
        @ConfigurationProperties(prefix = "datastore.datasource.hikari")
        DataSourceHolder<HikariDataSource> dataSourceHolder(DataStoreDataSourceProperties properties) {
            HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class);
            if (StringUtils.hasText(properties.getName())) {
                dataSource.setPoolName(properties.getName());
            }
            return new DataSourceHolder<>(dataSource);
        }

        protected static <T> T createDataSource(DataStoreDataSourceProperties properties, Class<? extends DataSource> type) {
            return (T) properties.initializeDataSourceBuilder().type(type).build();
        }
    }
}
